﻿using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Messaging;
using SimpleBoard.DependencyInjection;
using SimpleBoard.Designer.Messages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;

namespace SimpleBoard.Designer.ViewModels
{
    [InjectAs(InjectionType.Transient)]
    public class DesignerPageViewModel : ObservableRecipient, 
        IRecipient<CanvasSizeUpdateRequest>,
        IRecipient<CanvasBackgroundUpdateRequest>,
        IRecipient<CanvasPropertyRequest>
    {
        private double scale = 1;
        private int gridWidth = 800;
        private int gridHeight = 450;
        private int horizontalScrollPos;
        private int verticalScrollPos;
        private int horizontalScrollLimit;
        private int verticalScrollLimit;
        private int canvasWidth;
        private int canvasHeight;
        private int left;
        private int top;
        private Brush gridBackground = Brushes.White;
        private ScaleOptionViewModel selectedScale = null!;

        public DesignerPageViewModel()
        {
            IsActive = true;
            SelectedScale = ScaleOptions[3];
        }

        ~DesignerPageViewModel()
        {
            IsActive = false;
        }

        private void UpdateScale(ScaleOptionViewModel scaleOption)
        {
            Scale = scaleOption.Value;
        }

        private void UpdateView()
        {
            var gridActualWidth = gridWidth * scale;
            var gridActualHeight = gridHeight * scale;

            HorizontalScrollLimit = (int)gridActualWidth + canvasWidth;
            VerticalScrollLimit = (int)gridActualHeight + canvasHeight;

            Left = (canvasWidth - (int)gridActualWidth) / 2;
            Top = (canvasHeight - (int)gridActualHeight) / 2;

            HorizontalScrollPos = HorizontalScrollLimit / 2;
            VerticalScrollPos = VerticalScrollLimit / 2;
        }

        private void UpdateHorizontalScroll()
        {
            var gridActualWidth = gridWidth * scale;
            var origin = horizontalScrollLimit / 2;
            var center = (canvasWidth - (int)gridActualWidth) / 2;

            var offset = horizontalScrollPos - origin;
            Left = center + offset;
        }

        private void UpdateVerticalScroll()
        {
            var gridActualHeight = gridHeight * scale;
            var origin = verticalScrollLimit / 2;
            var center = (canvasHeight - (int)gridActualHeight) / 2;

            var offset = verticalScrollPos - origin;
            Top = center + offset;
        }

        public void UpdateCanvasSize(int width, int height) 
        { 
            canvasWidth = width; 
            canvasHeight = height;
            UpdateView();
        }

        public void Receive(CanvasSizeUpdateRequest message)
        {
            this.GridWidth = message.Width == 0 ? this.GridWidth : message.Width;
            this.GridHeight = message.Height == 0 ? this.GridHeight : message.Height;
            UpdateVerticalScroll();
            UpdateHorizontalScroll();
            UpdateView();
        }

        public void Receive(CanvasBackgroundUpdateRequest message)
        {
            this.GridBackground = message.Background;
        }

        public void Receive(CanvasPropertyRequest message)
        {
            message.Reply(new CanvasProperty(GridWidth, GridHeight, GridBackground));
        }

        /// <summary>
        /// 缩放率
        /// </summary>
        public double Scale
        {
            get => scale;
            set { this.SetProperty(ref scale, value); UpdateView(); }
        }

        /// <summary>
        /// 根容器宽度
        /// </summary>
        public int GridWidth
        {
            get => gridWidth;
            set => this.SetProperty(ref gridWidth, value);
        }

        /// <summary>
        /// 根容器高度
        /// </summary>
        public int GridHeight
        {
            get => gridHeight;
            set => this.SetProperty(ref gridHeight, value);
        }

        /// <summary>
        /// 水平滚动条位置
        /// </summary>
        public int HorizontalScrollPos
        {
            get => horizontalScrollPos;
            set { this.SetProperty(ref horizontalScrollPos, value); UpdateHorizontalScroll(); }
        }

        /// <summary>
        /// 垂直滚动条位置
        /// </summary>
        public int VerticalScrollPos
        {
            get => verticalScrollPos;
            set { this.SetProperty(ref verticalScrollPos, value); UpdateVerticalScroll(); }
        }

        /// <summary>
        /// 水平滚动条限制
        /// </summary>
        public int HorizontalScrollLimit
        {
            get => horizontalScrollLimit;
            set => this.SetProperty(ref horizontalScrollLimit, value);
        }

        /// <summary>
        /// 垂直滚动条限制
        /// </summary>
        public int VerticalScrollLimit
        {
            get => verticalScrollLimit;
            set => this.SetProperty(ref verticalScrollLimit, value);
        }

        public int Left
        {
            get => left;
            set => this.SetProperty(ref left, value);
        }

        public int Top
        {
            get => top;
            set => this.SetProperty(ref top, value);
        }

        public Brush GridBackground
        {
            get => gridBackground;
            set => this.SetProperty(ref gridBackground, value);
        }

        public ScaleOptionViewModel[] ScaleOptions => new ScaleOptionViewModel[]
        {
            new ScaleOptionViewModel{ DisplayName = "20%", Value = 0.2 },
            new ScaleOptionViewModel{ DisplayName = "50%", Value = 0.5 },
            new ScaleOptionViewModel{ DisplayName = "70%", Value = 0.7 },
            new ScaleOptionViewModel{ DisplayName = "100%", Value = 1 },
            new ScaleOptionViewModel{ DisplayName = "150%", Value = 1.5 },
            new ScaleOptionViewModel{ DisplayName = "200%", Value = 2 },
            new ScaleOptionViewModel{ DisplayName = "400%", Value = 4 },
        };

        public ScaleOptionViewModel SelectedScale
        {
            get => selectedScale;
            set { this.SetProperty(ref selectedScale, value); UpdateScale(value); }
        }

    }
}
